package com.liu.minio.utils;

import com.liu.minio.config.MinioProperties;
import io.minio.*;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ClassName: MinioFile
 * @Author: jdh
 * @CreateTime: 2022-04-15
 * @Description:
 */
@Configuration
@Slf4j
public class MinioFileUtil {

    @Resource
    private MinioProperties minioProperties;

    @Autowired
    private MinioClient minioClient;



    /**
     * 根据MultipartFile file上传文件
     * minio 采用文件流上传，可以换成下面的文件上传
     *
     * @param file       上传的文件
     */
    public String uploadFile(MultipartFile file) throws Exception {

        if (file == null || file.getSize() == 0 || file.isEmpty()) {
            throw new RuntimeException("上传文件为空，请重新上传");
        }

        // 获取上传的文件名
        String filename = file.getOriginalFilename();
        assert filename != null;
        //可以选择生成一个minio中存储的文件名称
        String minioFilename =
                new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/" + UUID.randomUUID().toString().toLowerCase(Locale.ROOT) + "_" + filename;

        PutObjectArgs build = PutObjectArgs.builder()
                .bucket(minioProperties.getBucketName()) //上传到指定桶里面
                .object(minioFilename)//文件在minio中存储的名字
                //p1:上传的文件流；p2:上传文件总大小；p3：上传的分片大小
                .stream(file.getInputStream(), file.getSize(), -1) //上传分片文件流大小，如果分文件上传可以采用这种形式
                .contentType(file.getContentType()) //文件的类型
                .build();


        ObjectWriteResponse objectWriteResponse = minioClient.putObject(build);

        return minioProperties.getUrl() + "/" + minioProperties.getBucketName() + "/" + minioFilename;
    }


    /**
     * 文件下载,通过http返回，即在浏览器下载
     *
     * @param response   http请求的响应对象
     * @param objectName 下载的文件名称
     */
    public void downloadFile(HttpServletResponse response, String objectName) throws Exception {
        if (response == null ||  !StringUtils.hasLength(objectName)) {
            throw new RuntimeException("下载文件参数不全！");
        }

        //获取一个下载的文件输入流操作
        GetObjectResponse objectResponse = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(minioProperties.getBucketName())
                        .object(objectName)
                        .build());

        OutputStream outputStream = response.getOutputStream();
        int len = 0;
        byte[] buf = new byte[1024 * 8];
        while ((len = objectResponse.read(buf)) != -1) {
            outputStream.write(buf, 0, len);
        }
        if (outputStream != null) {
            outputStream.close();
            outputStream.flush();
        }
        objectResponse.close();
    }




    private static final int MIN_MULTIPART_SIZE = 0;
    private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return
     */
    @SneakyThrows
    public boolean bucketExists(String bucketName) {
        BucketExistsArgs build = new BucketExistsArgs.Builder().bucket(bucketName).build();
        return minioClient.bucketExists(build);
    }

    /**
     * 创建存储桶
     *
     * @param bucketName 存储桶名称
     */
    @SneakyThrows
    public boolean makeBucket(String bucketName) {
        boolean flag = bucketExists(bucketName);
        if (!flag) {
            MakeBucketArgs build = new MakeBucketArgs.Builder().bucket(bucketName).build();
            minioClient.makeBucket(build);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 列出所有存储桶名称
     *
     * @return
     */
    @SneakyThrows
    public List<String> listBucketNames() {
        List<Bucket> bucketList = listBuckets();
        List<String> bucketListName = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            bucketListName.add(bucket.name());
        }
        return bucketListName;
    }

    /**
     * 列出所有存储桶
     *
     * @return
     */
    @SneakyThrows
    public List<Bucket> listBuckets() {
        return minioClient.listBuckets();
    }

}
